package city.spring.modules.system.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

/**
 * 角色、权限分组基础实体对象。
 * 给用户、用户组、部门继承该对象，因为这三个对象都拥有角色列表、权限列表两个信息
 *
 * @author HouKunLin
 */
@Data
@EqualsAndHashCode
public abstract class BaseRolePermissionEntity {
    /**
     * 当前对象所拥有的角色信息列表
     */
    @TableField(exist = false)
    protected List<RoleEntity> roles;
    /**
     * 当前对象所拥有的权限列表
     */
    @TableField(exist = false)
    protected List<PermissionEntity> permissions;

    /**
     * 收集权限信息，把 collection 集合中的权限代码收集到 set 中存放
     *
     * @param set        存储权限代码的集合
     * @param collection 拥有权限信息的集合
     * @param <T>        权限信息对象
     */
    public static <T extends GrantedAuthority> void collectionAuthorities(Set<String> set, Collection<T> collection) {
        collectionAuthorities(set, collection, false);
    }

    /**
     * 收集权限信息，把 collection 集合中的权限代码收集到 set 中存放
     *
     * @param set              存储权限代码的集合
     * @param collection       拥有权限信息的集合
     * @param isRoleCollection 标记 collection 集合是否是一个角色集合对象，如果是角色集合对象需要做特殊处理
     * @param <T>              权限信息对象，如果 isRoleCollection=true 则该对象应该为 RoleEntity 对象
     */
    public static <T extends GrantedAuthority> void collectionAuthorities(Set<String> set, Collection<T> collection, boolean isRoleCollection) {
        if (collection == null || set == null) {
            return;
        }
        Consumer<T> consumer;
        if (isRoleCollection) {
            // 当前集合列表是角色对象列表
            // 需要处理角色对象的权限信息，以免遗漏信息未处理
            consumer = entity -> {
                if (entity instanceof RoleEntity) {
                    RoleEntity roleEntity = (RoleEntity) entity;
                    // 取出角色对象的所有权限信息列表
                    List<PermissionEntity> permissions = roleEntity.getPermissions();
                    // 然后把这个角色的权限信息列表中的所有 权限代码 取出放入到 Set 对象中
                    collectionAuthorities(set, permissions, false);
                }
            };
        } else {
            consumer = (entity) -> {
            };
        }
        collectionAuthorities(set, collection, consumer);
    }

    /**
     * [重复代码提取为方法] 收集权限信息，把 collection 集合中的权限代码收集到 set 中存放
     *
     * @param set              存储权限代码的集合
     * @param collection       拥有权限信息的集合
     * @param itemAfterHandler 每条记录处理后的操作
     * @param <T>              权限信息对象
     */
    public static <T extends GrantedAuthority> void collectionAuthorities(Set<String> set, Collection<T> collection, Consumer<T> itemAfterHandler) {
        if (collection == null || set == null) {
            return;
        }
        if (itemAfterHandler == null) {
            itemAfterHandler = (entity) -> {
            };
        }
        for (T authority : collection) {
            if (authority != null) {
                set.add(authority.getAuthority());
                itemAfterHandler.accept(authority);
            }
        }
    }

    /**
     * 把权限、角色对象列表的 代码 信息写入到 Set 对象中
     *
     * @param set        代码结果存放对象
     * @param collection 权限、角色对象列表
     * @param <T>        权限、角色对象
     */
    public static <T extends BaseRolePermissionEntity> void collectionAll(Set<String> set, Collection<T> collection) {
        if (collection == null || set == null) {
            return;
        }
        for (T item : collection) {
            if (item != null) {
                set.addAll(item.getAllAuthorities());
            }
        }
    }

    /**
     * 当前对象所拥有的所有角色和权限代码信息
     */
    public Set<String> getAllAuthorities() {
        Set<String> allAuthorities = new LinkedHashSet<>();
        collectionAuthorities(allAuthorities, roles, true);
        collectionAuthorities(allAuthorities, permissions, false);
        return allAuthorities;
    }
}
